import { HttpContext } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, Optional } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ApiResToComponent, AppConfigService } from '@basic';
import { StartupService } from '@core';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { ALLOW_ANONYMOUS, DA_SERVICE_TOKEN, ITokenService, SocialOpenType, SocialService } from '@delon/auth';
import { SettingsService, _HttpClient } from '@delon/theme';
import { environment } from '@env/environment';
import { LoginData, LoginResult, VerifyCodeResult } from '@types';
import { finalize } from 'rxjs';
import { CacheService } from '@delon/cache';

@Component({
    selector: 'passport-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.less'],
    providers: [SocialService],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserLoginComponent implements OnInit, OnDestroy {
    constructor(
        private fb: FormBuilder,
        private router: Router,
        private settingsService: SettingsService,
        private socialService: SocialService,
        private appConfigService: AppConfigService,
        @Optional()
        @Inject(ReuseTabService)
        private reuseTabService: ReuseTabService,
        @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
        private startupSrv: StartupService,
        private http: _HttpClient,
        private cache: CacheService,
        private cdr: ChangeDetectorRef
    ) {
        const params: any = this.cache.getNone('login_params');
        this.form = this.fb.nonNullable.group({
            userName: [params?.userName ?? '', [Validators.required]],
            password: [params?.password ?? '', [Validators.required, Validators.minLength(5), Validators.maxLength(8)]],
            captcha: ['', [Validators.required]],
            uuid: ['', [Validators.required]],
            remember: [this.cache.getNone('login_remember') ?? false]
        });
    }

    // #region fields

    form: FormGroup;
    error = '';
    loading = false;

    // #region get captcha

    captchaEnabled = false;

    codeUrl = '';

    count = 0;
    interval$: any;

    /**
     * 是否展示密码
     */
    showPasswordFlag: boolean = false;

    /**
     * 是否记住密码
     */

    // #endregion

    ngOnInit() {
        this.getCaptcha();
    }

    /**
     * 展示密码
     */
    taggerShowPassword() {
        this.showPasswordFlag = !this.showPasswordFlag;
        this.cdr.detectChanges();
    }

    getCaptcha(): void {
        this.http
            .get(
                `${this.appConfigService.appApiHost}/code`,
                {},
                {
                    context: new HttpContext().set(ALLOW_ANONYMOUS, true)
                }
            )
            .subscribe((res: ApiResToComponent<VerifyCodeResult>) => {
                this.captchaEnabled = res.data?.captchaEnabled === undefined ? true : res.data.captchaEnabled;
                if (this.captchaEnabled) {
                    this.codeUrl = `data:image/gif;base64,${res.data?.img}`;
                    this.form.value.uuid = res.data?.uuid;
                    this.form.patchValue({ uuid: res.data?.uuid });
                }
                this.cdr.detectChanges();
            });
    }

    // #endregion

    submit(): void {
        const { userName, password, captcha, uuid, remember } = this.form.controls;
        userName.markAsDirty();
        userName.updateValueAndValidity();
        password.markAsDirty();
        password.updateValueAndValidity();
        captcha.markAsDirty();
        captcha.updateValueAndValidity();
        uuid.markAsDirty();
        uuid.updateValueAndValidity();
        remember.markAsDirty();
        remember.updateValueAndValidity();
        this.cache.set('login_remember', this.form.value.remember);
        if (this.form.value.remember) {
            this.cache.set('login_params', {
                userName: this.form.value.userName,
                password: this.form.value.password,
                remember: this.form.value.remember
            });
        } else {
            this.cache.set('login_params', null);
        }
        if (userName.invalid || password.invalid || captcha.invalid) {
            return;
        }

        // 默认配置中对所有HTTP请求都会强制 [校验](https://ng-alain.com/auth/getting-started) 用户 Token
        // 然一般来说登录请求不需要校验，因此加上 `ALLOW_ANONYMOUS` 表示不触发用户 Token 校验
        this.loading = true;
        this.cdr.detectChanges();
        this.http
            .post(
                `${this.appConfigService.appApiHost}/auth/login`,
                {
                    uuid: this.form.value.uuid,
                    username: this.form.value.userName,
                    password: this.form.value.password,
                    code: this.form.value.captcha
                } as LoginData,
                null,
                {
                    context: new HttpContext().set(ALLOW_ANONYMOUS, true)
                }
            )
            .pipe(
                finalize(() => {
                    this.loading = false;
                    this.cdr.detectChanges();
                })
            )
            .subscribe((res: ApiResToComponent<LoginResult>) => {
                if (res.msg !== '操作成功') {
                    captcha.setValue('');
                    this.getCaptcha();
                    this.error = res.msg ?? '';
                    this.cdr.detectChanges();
                    return;
                }
                // 清空路由复用信息
                this.reuseTabService.clear();
                // 设置用户Token信息
                // TODO: Mock expired value
                // res.user.expired = +new Date() + 1000 * 60 * 5;
                this.tokenService.set({ token: res.data?.access_token });
                // 重新获取 StartupService 内容，我们始终认为应用信息一般都会受当前用户授权范围而影响
                this.startupSrv.load().subscribe(() => {
                    let url = this.tokenService.referrer!.url || '/';
                    if (url.includes('/passport')) {
                        url = '/';
                    }
                    this.router.navigateByUrl(url).then();
                });
            });
    }

    // #region social

    open(type: string, openType: SocialOpenType = 'href'): void {
        let url = ``;
        let callback = ``;
        if (environment.production) {
            callback = `https://ng-alain.github.io/ng-alain/#/passport/callback/${type}`;
        } else {
            callback = `http://localhost:4200/#/passport/callback/${type}`;
        }
        switch (type) {
            case 'auth0':
                url = `//cipchk.auth0.com/login?client=8gcNydIDzGBYxzqV0Vm1CX_RXH-wsWo5&redirect_uri=${decodeURIComponent(callback)}`;
                break;
            case 'github':
                url = `//github.com/login/oauth/authorize?client_id=9d6baae4b04a23fcafa2&response_type=code&redirect_uri=${decodeURIComponent(
                    callback
                )}`;
                break;
            case 'weibo':
                url = `https://api.weibo.com/oauth2/authorize?client_id=1239507802&response_type=code&redirect_uri=${decodeURIComponent(
                    callback
                )}`;
                break;
        }
        if (openType === 'window') {
            this.socialService
                .login(url, '/', {
                    type: 'window'
                })
                .subscribe(res => {
                    if (res) {
                        this.settingsService.setUser(res);
                        this.router.navigateByUrl('/');
                    }
                });
        } else {
            this.socialService.login(url, '/', {
                type: 'href'
            });
        }
    }

    // #endregion

    ngOnDestroy(): void {
        if (this.interval$) {
            clearInterval(this.interval$);
        }
    }
}
